#include "GlobalHead.h"
#include "ToolsCallback_Camera.h"
#include "part/PartPathCamera.h"
#include "Gui_Application.h"
#include "ViewProvider.h"
#include "ViewProviderPathCamera.h"
#include "CustomPlayer.h"

using namespace PartGui;
using namespace Gui;

TYPESYSTEM_SOURCE(PathCamera,Tools)
//PROPERTY_SOURCE(Gui::PathCamera,Gui::Tools)

PathCamera::PathCamera()
:Tools("PathCamera"),pCurve(NULL),pCam(NULL),elapsedTime(0.0f),parent(NULL)
,playPause(FALSE),pViewPartCam(NULL)
{
	mTM = CCustomPlayer::Instance().GetTimeManager();
}
PathCamera::~PathCamera()
{ 

}
CKBOOL PathCamera::action(CKRenderContext*)
{
	mouseState ms = getCurrentMousetStateType();
	switch (ms)
	{
	case LBUTTONDOWN:
		{
			if(playPause)
				playPause = FALSE;
			else
			{
				pCurve = pViewPartCam->getCurrentCurve();
				mTotalTime = pViewPartCam->getTotalTime();
				playPause = TRUE;
			}

		}
		break;
	case RBUTTONDOW:
		{
			pCurve = pViewPartCam->getCurrentCurve();
			mTotalTime = pViewPartCam->getTotalTime();
			elapsedTime = 0;
           playPause = TRUE;
		}
		break;
	}

	if(playPause)
 	elapsedTime += (mTM->GetLastDeltaTime()/100.0f);
 
 	float progression =  elapsedTime / mTotalTime;
     if(progression > 1.0f) progression = 1.0f;
 
 
 	if(elapsedTime > mTotalTime)
 		elapsedTime = 0;
 
	
	if (pathtype == NO_CIRCLE)
	{
		SetCurveStep(progression,TRUE);
	}else if (pathtype == CIRCLE)
	{
		SetCurveStepCircle(progression);
	}
	
	
    return CK_OK;
}
void PathCamera::initPath()
{

}
void PathCamera::addCallBack(Tools* tl)
{
	if(!pDocumentObject)
	return;

	Gui::ViewProvider* pView =  Gui_Application::instance->getViewProvider(pDocumentObject);
	if(pView->getTypeId().isDerivedFrom(PartGui::ViewProviderPathCamera::getClassTypeId()))
	{
		pViewPartCam = static_cast<PartGui::ViewProviderPathCamera*>(pView);
	}


	CCustomPlayer::Instance().setActiveCamera(pDocumentObject);

	

  	Tools::addCallBack(tl);
}
void PathCamera::removeCallBack(Tools* tl)
{
	Tools::removeCallBack(tl);
}
void PathCamera::SetCurveStep(float x,CKBOOL follow)
{
	if(!pCurve)
		return;

	VxVector pos;

	//pCurve->GetPos(x,&pos);
	pCurve->getPositionOnCurve(x,&pos);

    pDocumentObject->setObjectPosition(pos);

	// next/previous
	VxVector nextpos,prevpos;
	pCurve->getPositionOnCurve(x+0.01f,&nextpos);
	pCurve->getPositionOnCurve(x-0.01f,&prevpos);

     VxVector up = VxVector::axisY();
	 if(follow) {
		 VxVector dir = nextpos-prevpos;
		 if (dir.SquareMagnitude()>0.00000001f) {
			 dir.Normalize();
			 up = BB_Orientate(pDocumentObject, dir/*, 5, 0, up, 1.0f, TRUE*/);
		 }
	 }
}

void PathCamera::SetCurveStepCircle(float x)
{
	if(!pCurve)
		return;

	VxVector pos;

	//pCurve->GetPos(x,&pos);
	pCurve->getPositionOnCurve(x,&pos);

	pDocumentObject->setObjectPosition(pos);

	// next/previous
	VxVector nextpos,prevpos,currpos;
	pCurve->getPositionOnCurve(x+0.01f,&nextpos);
	pCurve->getPositionOnCurve(x-0.01f,&prevpos);
	pCurve->getPositionOnCurve(x,&currpos);

	VxVector up = VxVector::axisY();
	
	{
		VxVector dir = originCircle - currpos;
		if (dir.SquareMagnitude()>0.00000001f) {
			dir.Normalize();
			up = BB_Orientate(pDocumentObject, dir/*, 5, 0, up, 1.0f, TRUE*/);
		}
	}
}
VxVector PathCamera::BB_Orientate(App::DocumentObject *ent, VxVector dir, int dirMode, float roll, VxVector up, float speedValue, CKBOOL k, CKBOOL unitaryScale)
{

// 	VxVector scale;
// 	if( !unitaryScale ) ent->getScale( scale );

	if( (dirMode & 1) == 0 ) dir = -dir;
	VxVector old_dir, right;

	//--- tend to be Y world axis
	up.x *= 0.5f; up.z *= 0.5f;

	//--- direction mode dependant
	switch( dirMode ){

  case 5: //  Z
  case 6: // -Z
	  { 
		  if(up.x>1.5f) ent->getOrientation(NULL,&up); // memorize first up vector
		  ent->getOrientation( &old_dir, NULL);

		  dir = old_dir + speedValue * ( dir - old_dir );
		  right = CrossProduct(up, dir);
		  up = CrossProduct(dir, right);

		  dir.Normalize();
		  right.Normalize();
		  up.Normalize();

		  ent->setOrientation( &dir , &up, &right, NULL, k );
		  if( roll != 0.0f ) 
			  ent->rotate( 0, 0, 1, roll, ent, k);

	  } break;

  case 1: //  X
  case 2: // -X
	  {
		  if(up.x>1.5f) ent->getOrientation(NULL, &up); // memorize first up vector

		  ent->getOrientation( NULL, NULL, &old_dir );

		  dir = old_dir + speedValue * ( dir - old_dir );
		  right = CrossProduct(dir, up);
		  up = CrossProduct(right, dir);

		  dir.Normalize();
		  right.Normalize();
		  up.Normalize();

		  ent->setOrientation( &right , &up, &dir, NULL, k );
		  if( roll != 0.0f )
			  ent->rotate( 1, 0, 0, roll, ent, k);

	  } break;

  case 3: //  Y
  case 4: // -Y
	  {
		  if(up.x>1.5f) {
			  up = VxVector::axisX();
			  //ent->GetOrientation(&up, NULL); // memorize first up vector
		  }


		  ent->getOrientation( NULL, &old_dir );
		  dir = old_dir + speedValue * ( dir - old_dir );
		  right = CrossProduct(up, dir);
		  up = CrossProduct(dir, right);

		  dir.Normalize();
		  right.Normalize();
		  up.Normalize();

		  ent->setOrientation( &right , &dir, &up, NULL, k );
		  if( roll != 0.0f ) ent->rotate( 0, 1, 0, roll, ent, k);

	  } break;

	}

// 	if( !unitaryScale )
// 		ent->setScale( scale );


	return up;
}

TYPESYSTEM_SOURCE(FreeCamera,Tools)

FreeCamera::FreeCamera()
:Tools("FreeCamera"),m_IsLButtonUp(false),m_IsLButtonDown(false)
{

}
FreeCamera::~FreeCamera()
{

}

CKBOOL FreeCamera::action(CKRenderContext*)
{

	Vx2DVector tempos;
	toolInput->GetMousePosition(tempos);

	if(toolInput->IsMouseButtonDown(CK_MOUSEBUTTON_LEFT) && m_IsLButtonDown == false)
	{
		m_IsLButtonDown = true;
		mMouseDownPositon = tempos;

	}else if(toolInput->IsMouseButtonDown(CK_MOUSEBUTTON_LEFT) == false && m_IsLButtonDown == true)
	{
		m_IsLButtonDown = false;
		mMouseDownPositon = mMouseUpPosition;
	}

	VxVector movePos;
	toolInput->GetMouseRelativePosition(movePos);
	if(movePos.x != 0 || movePos.y != 0)
	{
		if(m_IsLButtonDown)
		{
           pDocumentObject->rotate(0,1,0,-movePos.x,NULL);
		    pDocumentObject->rotate(1,0,0,-movePos.y,pDocumentObject);
		}
	}


	
	
	if(toolInput->IsKeyDown(CKKEY_W))
		pDocumentObject->translateObject(0,0,1,pDocumentObject,FALSE);
	if(toolInput->IsKeyDown(CKKEY_S))
		pDocumentObject->translateObject(0,0,-1,pDocumentObject,FALSE);
	if(toolInput->IsKeyDown(CKKEY_A))
		pDocumentObject->translateObject(-1,0,0,pDocumentObject,FALSE);
	if(toolInput->IsKeyDown(CKKEY_D))
		pDocumentObject->translateObject(1,0,0,pDocumentObject,FALSE);



   return  CK_OK;
}

void FreeCamera::addCallBack(Tools* tl)
{
	if(!pDocumentObject)
		return;

   CCustomPlayer::Instance().setActiveCamera(pDocumentObject);

	Tools::addCallBack(tl);
}
void FreeCamera::removeCallBack(Tools* tl)
{
	Tools::removeCallBack(tl);
}

